package dev.ece.util.tools;

import java.awt.Color;
import java.awt.Graphics;
import java.awt.color.ColorSpace;
import java.awt.image.BufferedImage;
import java.awt.image.ColorModel;
import java.awt.image.ComponentColorModel;
import java.awt.image.DataBuffer;
import java.awt.image.DataBufferByte;
import java.awt.image.Raster;
import java.awt.image.WritableRaster;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.util.Hashtable;

import javax.imageio.ImageIO;

import org.lwjgl.opengl.GL11;
import org.lwjgl.opengl.GL20;

import dev.ece.util.tools.ploy.TexturePloy;

/**
 * 
 * 说明：
 *
 * TextureLoader.java
 *
 * @author DEVILIVED
 * 
 * 版本信息 v1.0
 * 
 * 2012-9-5
 *
 * 修改历史 
 *
 * Copyright 2012, DEVILIVED Inc.
 */
public class TextureLoader {


    private static final ColorModel glAlphaColorModel = new ComponentColorModel(ColorSpace.getInstance(ColorSpace.CS_sRGB),
            new int[] {8,8,8,8},
            true,
            false,
            ComponentColorModel.TRANSLUCENT,
            DataBuffer.TYPE_BYTE);

    private static final ColorModel glColorModel = new ComponentColorModel(ColorSpace.getInstance(ColorSpace.CS_sRGB),
            new int[] {8,8,8,0},
            false,
            false,
            ComponentColorModel.OPAQUE,
            DataBuffer.TYPE_BYTE);
    
	public static int bindTextureImage(BufferedImage image, TexturePloy textureStrategy) {
    	int texture = GL11.glGenTextures();
    	GL11.glBindTexture(GL11.GL_TEXTURE_2D, texture);
    	textureStrategy.beforeGlTexImage2D();
    	glTexImage2D(GL11.GL_TEXTURE_2D, image);
    	textureStrategy.afterGlTexImage2D();
        GL11.glBindTexture(GL11.GL_TEXTURE_2D, 0);
        return texture;
    }
	
	public static int bindTextureCubeImage(BufferedImage[] images, TexturePloy textureStrategy) {
    	int texture = GL11.glGenTextures();
    	GL11.glBindTexture(GL20.GL_TEXTURE_CUBE_MAP, texture);
    	textureStrategy.beforeGlTexImage2D();
    	for(int i=0; i<images.length; i++) {
	    	glTexImage2D(GL20.GL_TEXTURE_CUBE_MAP_POSITIVE_X + i, images[i]);
    	}
    	textureStrategy.afterGlTexImage2D();
        GL11.glBindTexture(GL20.GL_TEXTURE_CUBE_MAP, 0);
        return texture;
    }
	
	public static ByteBuffer loadImageToByteBuffer(BufferedImage image) {
		ByteBuffer imageBuffer = null;
	    WritableRaster raster = null;
	    BufferedImage texImage = null;
	    if(image.getColorModel().hasAlpha()) {
            raster = Raster.createInterleavedRaster(DataBuffer.TYPE_BYTE, image.getWidth(), image.getHeight(), 4, null);
            texImage = new BufferedImage(glAlphaColorModel, raster, false, new Hashtable<String, Object>());
	    } else {
            raster = Raster.createInterleavedRaster(DataBuffer.TYPE_BYTE, image.getWidth(), image.getHeight(), 3, null);
            texImage = new BufferedImage(glColorModel,raster,false,new Hashtable<String, Object>());
	    }
	    Graphics g = texImage.getGraphics();
        g.setColor(new Color(0f,0f,0f,0f));
        g.fillRect(0, 0, image.getWidth(), image.getHeight());
        g.drawImage(image, 0, 0,null);
        byte[] data = ((DataBufferByte) texImage.getRaster().getDataBuffer()).getData();
        
        imageBuffer = ByteBuffer.allocateDirect(data.length);
        imageBuffer.order(ByteOrder.nativeOrder());
        imageBuffer.put(data, 0, data.length);
        imageBuffer.flip();
        return imageBuffer;
	}
	
	public static void glTexImage2D(int target, BufferedImage image) {
		ByteBuffer imageBuffer = null;
	    WritableRaster raster = null;
	    BufferedImage texImage = null;
	    int srcPixelFormat = 0;
	    if(image.getColorModel().hasAlpha()) {
	    	srcPixelFormat = GL11.GL_RGBA;
            raster = Raster.createInterleavedRaster(DataBuffer.TYPE_BYTE, image.getWidth(), image.getHeight(), 4, null);
            texImage = new BufferedImage(glAlphaColorModel, raster, false, new Hashtable<String, Object>());
	    } else {
	    	srcPixelFormat = GL11.GL_RGB;
            raster = Raster.createInterleavedRaster(DataBuffer.TYPE_BYTE, image.getWidth(), image.getHeight(), 3, null);
            texImage = new BufferedImage(glColorModel,raster,false,new Hashtable<String, Object>());
	    }
	    Graphics g = texImage.getGraphics();
        g.setColor(new Color(0f,0f,0f,0f));
        g.fillRect(0, 0, image.getWidth(), image.getHeight());
        g.drawImage(image, 0, 0,null);
        g.dispose();
        byte[] data = ((DataBufferByte) texImage.getRaster().getDataBuffer()).getData();

        imageBuffer = ByteBuffer.allocateDirect(data.length);
        imageBuffer.order(ByteOrder.nativeOrder());
        imageBuffer.put(data, 0, data.length);
        imageBuffer.flip();
        GL11.glTexImage2D(
        		target, 0, srcPixelFormat, 
        		image.getWidth(), image.getHeight(), 
        		0, srcPixelFormat, GL11.GL_UNSIGNED_BYTE, 
        		imageBuffer);
	}
	
	public static final int loadTextureCubeMap(File[] files, TexturePloy texturePloy) throws IOException {
		int texture = 0;
		BufferedImage[] images = new BufferedImage[files.length];
		InputStream is = null;
		for(int i=0; i<images.length; i++) {
			is = new FileInputStream(files[i]);
			images[i] = ImageIO.read(is);
			is.close();
		}
		texture = bindTextureCubeImage(images, texturePloy);
        return texture;
	}
	
	public static final int loadTextureCubeMap(String[] filenames, TexturePloy texturePloy) throws IOException {
		File[] files = new File[filenames.length];
		for(int i=0; i<filenames.length; i++) {
			files[i] = new File(filenames[i]);
		}
		return loadTextureCubeMap(files, texturePloy);
	}
	
}
